package com.info.zhiduoduo.admin.service;

import com.baomidou.mybatisplus.mapper.Condition;
import com.beust.jcommander.internal.Lists;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.info.zhiduoduo.admin.model.formbean.partner.AddEditSubPartnerFormBean;
import com.info.zhiduoduo.admin.model.formbean.partner.MonthlyCostListFormBean;
import com.info.zhiduoduo.admin.model.formbean.partner.SettleCostFormBean;
import com.info.zhiduoduo.admin.model.formbean.partner.SubPartnerListFormBean;
import com.info.zhiduoduo.common.constants.Constants;
import com.info.zhiduoduo.common.constants.SmartResult;
import com.info.zhiduoduo.common.constants.StatusMsg;
import com.info.zhiduoduo.common.constants.partner.PartnerCrowdSub;
import com.info.zhiduoduo.common.constants.partner.PartnerCrowdsourceCostState;
import com.info.zhiduoduo.common.constants.partner.PartnerMonthlyCrowdCostState;
import com.info.zhiduoduo.common.exception.Asserts;
import com.info.zhiduoduo.common.formbean.BaseSimpleFormBean;
import com.info.zhiduoduo.common.utils.DateUtil;
import com.info.zhiduoduo.common.utils.NumberUtil;
import com.info.zhiduoduo.repository.dto.crowdsource.CrowdsourceProjectSumDto;
import com.info.zhiduoduo.repository.dto.partner.PartnerCompanyMonthlyCrowdourceCostDto;
import com.info.zhiduoduo.repository.dto.partner.PartnerCrowdsourceSubDto;
import com.info.zhiduoduo.repository.dto.partner.PartnerDetailDto;
import com.info.zhiduoduo.repository.dto.partner.PartnerMonthlyCrowdsourceCostDto;
import com.info.zhiduoduo.repository.dto.partner.PartnerNameDto;
import com.info.zhiduoduo.repository.entity.partner.PartnerAccount;
import com.info.zhiduoduo.repository.entity.partner.PartnerCompanyMonthlyCrowdCost;
import com.info.zhiduoduo.repository.entity.partner.PartnerCrowdsourceSub;
import com.info.zhiduoduo.repository.entity.partner.PartnerMonthlyCrowdCost;
import com.info.zhiduoduo.repository.mapper.crowdsource.CrowdsourceProjectMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerCompanyMonthlyCrowdCostMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerCrowdsourceSubMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerMonthlyCrowdCostMapper;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.validation.Valid;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class PartnerCrowdsourceCostService {

	@Autowired
	PartnerMapper partnerMapper;
	@Resource
	PartnerCrowdsourceSubMapper partnerCrowdsourceSubMapper;
	@Resource
	CrowdsourceProjectMapper crowdsourceProjectMapper;
	@Resource
	PartnerMonthlyCrowdCostMapper partnerMonthlyCrowdCostMapper;
	@Resource
	PartnerCompanyMonthlyCrowdCostMapper partnerCompanyMonthlyCrowdCostMapper;

	public SmartResult<PartnerCrowdsourceSubDto> getCrowdsourceSubPartnerList(BaseSimpleFormBean<SubPartnerListFormBean> formBean) {
		@Valid SubPartnerListFormBean reqdata = formBean.getReqdata();
		if (reqdata == null) return SmartResult.ofErrorParam();

		int partnerid = reqdata.getPartnerid();

		List<PartnerCrowdsourceSubDto> list = partnerCrowdsourceSubMapper.findSubListByUpId(partnerid);
		return SmartResult.success(list);
	}

	public SmartResult addEditCrowdsourceSubPartner(BaseSimpleFormBean<AddEditSubPartnerFormBean> formBean) {
		@Valid AddEditSubPartnerFormBean reqdata = formBean.getReqdata();
		if (reqdata == null) return SmartResult.ofErrorParam();

		int id = reqdata.getId();
		int partnerid = reqdata.getPartnerid();
		int subPartnerid = reqdata.getSubPartnerid();
		Integer state = reqdata.getState();

		PartnerDetailDto partner = partnerMapper.getPartnerDetail(partnerid);
		PartnerDetailDto subPartner = partnerMapper.getPartnerDetail(subPartnerid);
		if (partner == null || partner.getState() != Constants.partner_state_2 || partner.getRealnameAuth() != Constants.partner_auth_4 ||
				subPartner == null || subPartner.getState() != Constants.partner_state_2 ||
				subPartner.getRealnameAuth() != Constants.partner_auth_4) {
			return SmartResult.fail(StatusMsg.StatusMsg_501);
		}

		if (id == 0) {
			PartnerCrowdsourceSub partnerSub = new PartnerCrowdsourceSub();

			//检查重复绑定
			PartnerCrowdsourceSubDto exist = partnerCrowdsourceSubMapper.findUpPartnerBySubId(subPartnerid);
			if (exist != null) return SmartResult.fail(StatusMsg.StatusMsg_516);

			//检查循环绑定:  防止A->B->A的情况
			PartnerCrowdsourceSubDto exist2 = partnerCrowdsourceSubMapper.findByUpIdAndSubId(subPartnerid, partnerid);
			if (exist2 != null) return SmartResult.fail(StatusMsg.StatusMsg_517);

			partnerSub.setPartnerid(partnerid).setSubPartnerid(subPartnerid).setState(state).insert();

			/*if (partnerSub.insert()) {
				//发送模板消息给上级合伙人
				wxPartnerMessageService.noticeSubPartnerAdded(partnerSubMapper.findById(partnerSub.getId()));

				return SmartResult.success(partnerSub.getId());
			}*/
			return SmartResult.success();
		} else {
			PartnerCrowdsourceSub partnerSub = new PartnerCrowdsourceSub().selectById(id);
			if (partnerSub == null) return SmartResult.ofErrorParam();

			partnerSub.setPartnerid(partnerid).setSubPartnerid(subPartnerid).setState(state);
			if (partnerSub.updateById()) return SmartResult.success(partnerSub.getId());
		}
		return SmartResult.ofOptFail();
	}

	public SmartResult delCrowdsourceSubPartner(BaseSimpleFormBean<Integer> formBean) {
		@Valid Integer id = formBean.getReqdata();
		new PartnerCrowdsourceSub().deleteById(id);
		return SmartResult.success();
	}

	public SmartResult<PartnerNameDto> getValidCrowdsourceSubPartnerList(BaseSimpleFormBean<String> formBean) {
		@Valid String name = formBean.getReqdata();
		List<PartnerNameDto> list = partnerMapper.findValidCrowdsourceSubPartnerList(name);
		return SmartResult.success(list);
	}

	public SmartResult<PartnerNameDto> getValidCrowdsourcePartnerList(BaseSimpleFormBean<String> formBean) {
		@Valid String name = formBean.getReqdata();
		List<PartnerNameDto> list = partnerMapper.findValidCrowdsourcePartnerList(name);
		return SmartResult.success(list);
	}

	public SmartResult<PartnerMonthlyCrowdsourceCostDto> listMonthlyCost(BaseSimpleFormBean<MonthlyCostListFormBean> formBean) {
		@Valid MonthlyCostListFormBean reqdata = formBean.getReqdata();
		Page<PartnerMonthlyCrowdsourceCostDto> page = PageHelper.startPage(formBean.getPage(), formBean.getRows());
		partnerMonthlyCrowdCostMapper.list(reqdata.getPartnerid(), reqdata.getName(), reqdata.getState(), reqdata.getFrom(),
				reqdata.getTo());
		return SmartResult.ofPage(page);
	}

	public SmartResult<PartnerCompanyMonthlyCrowdourceCostDto> listCompanyMonthlyCost(BaseSimpleFormBean<Integer> formBean) {
		@Valid Integer costId = formBean.getReqdata();
		List<PartnerCompanyMonthlyCrowdourceCostDto> list = partnerCompanyMonthlyCrowdCostMapper.listByCostId(costId);
		return SmartResult.success(list);
	}

	public SmartResult settleCost(BaseSimpleFormBean<SettleCostFormBean> formBean) {
		@Valid SettleCostFormBean reqdata = formBean.getReqdata();
		PartnerMonthlyCrowdCost crowdCost = new PartnerMonthlyCrowdCost().selectById(reqdata.getId());
		Asserts.notNull(crowdCost, StatusMsg.StatusMsg_101);
		Asserts.isTrue(NumberUtil.equals(crowdCost.getState(), PartnerCrowdsourceCostState.UNSETTLED), StatusMsg.StatusMsg_522);

		crowdCost.setState(PartnerCrowdsourceCostState.WITHDRAWED).setReceipt(reqdata.getReceipt()).setSettleTime(new Date()).setAdminid(formBean.getUserid()).updateById();
		return SmartResult.success();
	}

	public void recordPartnerCrowdsourceCost() {
		recordPartnerCrowdsourceCost(null);
	}

	public List<PartnerMonthlyCrowdCost> recordPartnerCrowdsourceCost(Date month) {
		if (month == null) month = DateUtil.getLastMonthBeginDate();

		List<PartnerNameDto> validCrowdsourcePartnerList = partnerMapper.findValidCrowdsourcePartnerList(null);
		log.info("计算合伙人每月众包成本分成------总合伙人数量:{}", validCrowdsourcePartnerList.size());
		List<PartnerMonthlyCrowdCost> list = Lists.newArrayList();
		for (PartnerNameDto partnerNameDto : validCrowdsourcePartnerList) {
			int partnerid = partnerNameDto.getPartnerid();
			list.add(recordPartnerCrowdsourceCost(partnerid, month));
		}
		return list;
	}

	/**
	 * 计算合伙人月份众包成本分成
	 * @param partnerid
	 * @param month
	 * @return
	 */
	public PartnerMonthlyCrowdCost recordPartnerCrowdsourceCost(int partnerid, Date month) {
		PartnerAccount partnerAccount = new PartnerAccount().selectOne(Condition.create().eq("partnerid", partnerid));
		if (partnerAccount == null) return null;

		Date beginDate = DateUtil.getStartDayOfMonth(month);
		PartnerMonthlyCrowdCost crowdCost = new PartnerMonthlyCrowdCost().selectOne(Condition.create().eq("partnerid", partnerid).eq("month", month));
		if (crowdCost == null) {
			crowdCost = new PartnerMonthlyCrowdCost().setMonth(beginDate)
													 .setPartnerid(partnerid)
													 .setCrowdCostPrimaryRate(partnerAccount.getCrowdCostPrimaryRate())
													 .setCrowdCostSecondaryRate(partnerAccount.getCrowdCostSecondaryRate())
													 .setCrowdCostSecondaryAmount(partnerAccount.getCrowdCostSecondaryAmount())
													 .setState(PartnerMonthlyCrowdCostState.CREATED);
		}
		// 实际成本比例
		CrowdsourceProjectSumDto partnerMonthTotalAmount = getCrowdPartnerMonthTotalAmount(partnerid, month);
		BigDecimal totalProjectTotalAmount = partnerMonthTotalAmount.getProjectTotalAmount();
		double actualCrowdCostRate = 0d;
		if (totalProjectTotalAmount.compareTo(partnerAccount.getCrowdCostSecondaryAmount()) > 0) {
			actualCrowdCostRate = partnerAccount.getCrowdCostSecondaryRate();
		} else {
			actualCrowdCostRate = partnerAccount.getCrowdCostPrimaryRate();
		}
		crowdCost.setTotalProjectAmount(totalProjectTotalAmount)
				.setActualCrowdCostRate(actualCrowdCostRate);
		// 插入数据
		crowdCost.insertOrUpdate();

		// 自己关联的企业数据
		List<PartnerCompanyMonthlyCrowdCost> ownCompList = crowdsourceProjectMapper.listProjectCostGroupByPartnerCompid(partnerid + "",
				month);
		BigDecimal ownProjectAmount = BigDecimal.ZERO;
		BigDecimal ownProjectTaxfee = BigDecimal.ZERO;
		BigDecimal ownProfit = BigDecimal.ZERO;
		for (PartnerCompanyMonthlyCrowdCost ownCompCost : ownCompList) {
			PartnerCompanyMonthlyCrowdCost monthCompCost = new PartnerCompanyMonthlyCrowdCost().selectOne(Condition.create()
																												   .eq("compid", ownCompCost.getCompid())
																												   .eq("month", month)
																												   .eq("partner_cost_id", crowdCost.getId())
																												   .eq("sub", PartnerCrowdSub.OWN));
			if (monthCompCost != null) {
				ownCompCost.setId(monthCompCost.getId());
			}
			ownCompCost.setPartnerCostId(crowdCost.getId()).setSub(PartnerCrowdSub.OWN);
			calcPartnerCompanyCrowdsourceCost(ownCompCost, actualCrowdCostRate);
			ownProjectAmount = ownProjectAmount.add(ownCompCost.getProjectAmount());
			ownProjectTaxfee = ownProjectTaxfee.add(ownCompCost.getProjectTaxfee());
			ownProfit = ownProfit.add(ownCompCost.getProfit());
			ownCompCost.insertOrUpdate();
		}

		// 下级合伙人关联的企业数据
		BigDecimal subProjectAmount = BigDecimal.ZERO;
		BigDecimal subProjectTaxfee = BigDecimal.ZERO;
		BigDecimal subProfit = BigDecimal.ZERO;
		List<PartnerCrowdsourceSubDto> subList = partnerCrowdsourceSubMapper.findSubListByUpId(partnerid);
		if (!CollectionUtils.isEmpty(subList)) {
			List<Integer> subIds = subList.stream().map(PartnerCrowdsourceSubDto::getSubPartnerid).collect(Collectors.toList());
			List<PartnerCompanyMonthlyCrowdCost> subCompList = crowdsourceProjectMapper.listProjectCostGroupByPartnerCompid(
					StringUtils.join(subIds, ","), month);
			for (PartnerCompanyMonthlyCrowdCost subCompCost : subCompList) {
				PartnerCompanyMonthlyCrowdCost subPartnerCompCost = new PartnerCompanyMonthlyCrowdCost().selectOne(Condition.create()
																															.eq("compid", subCompCost.getCompid())
																															.eq("month", month)
																															.eq("partner_cost_id", crowdCost.getId())
																															.eq("sub", PartnerCrowdSub.SUB));
				if (subPartnerCompCost != null) {
					subCompCost.setId(subPartnerCompCost.getId());
				}
				subCompCost.setPartnerCostId(crowdCost.getId()).setSub(PartnerCrowdSub.SUB);
				calcPartnerCompanyCrowdsourceCost(subCompCost, actualCrowdCostRate);
				subProjectAmount = subProjectAmount.add(subCompCost.getProjectAmount());
				subProjectTaxfee = subProjectTaxfee.add(subCompCost.getProjectTaxfee());
				subProfit = subProfit.add(subCompCost.getProfit());
				subCompCost.insertOrUpdate();
			}
		}
		// 更新整体数据
		crowdCost.setOwnProjectAmount(ownProjectAmount)
				.setOwnProjectTaxfee(ownProjectTaxfee)
				.setOwnProfit(ownProfit)
				.setSubProjectAmount(subProjectAmount)
				.setSubProjectTaxfee(subProjectTaxfee)
				.setSubProfit(subProfit)
				.setTotalProfit(ownProfit.add(subProfit));
		crowdCost.updateById();
		return crowdCost;
	}

	/**
	 * 获取指定合伙人在指定月份的业绩总项目款, 包含两个部分: 他自己关联的企业的总项目款 + 他的下级合伙人关联的企业总项目款
	 *
	 * @param partnerid
	 * @param month
	 * @return
	 */
	private CrowdsourceProjectSumDto getCrowdPartnerMonthTotalAmount(int partnerid, Date month) {
		List<Integer> list = partnerCrowdsourceSubMapper.findSubListByUpId(partnerid)
				.stream()
				.map(PartnerCrowdsourceSubDto::getSubPartnerid)
				.collect(Collectors.toList());
		list.add(partnerid);
		return crowdsourceProjectMapper.sumMonthTotalAmountByCrowdsourcePartner(StringUtils.join(list, ","), null, month);
	}

	/**
	 * 计算合伙人关联的企业月度众包项目成本.
	 * <p> 根据sub字段确定计算的是合伙人自己关联的企业 还是 他的下级合伙人关联的企业.
	 *
	 * @param compCrowdCost
	 * @param ownActualCrowdCostRate 当前合伙人自己的实际众包成本比例
	 */
	private void calcPartnerCompanyCrowdsourceCost(PartnerCompanyMonthlyCrowdCost compCrowdCost, double ownActualCrowdCostRate) {
		// 获取企业真实保证金比例
		Integer compid = compCrowdCost.getCompid();
		Integer partnerid = compCrowdCost.getPartnerid();
		Date month = compCrowdCost.getMonth();
		// 如果没有 开启保证金功能, 则保证金比例为0
		double actualDepositRate = 0;
		if (NumberUtil.equals(compCrowdCost.getDepositFlag(), 2)) {
			CrowdsourceProjectSumDto crowdsourceProjectSumDto = crowdsourceProjectMapper.sumMonthTotalAmountByCrowdsourcePartner(
					partnerid + "", compid, month);
			BigDecimal totalAmount =
					crowdsourceProjectSumDto.getProjectTotalAmount().add(crowdsourceProjectSumDto.getProjectTotalTaxfee());
			BigDecimal secondaryMonthlyAmount = compCrowdCost.getSecondaryMonthlyAmount();
			if (secondaryMonthlyAmount != null && totalAmount.compareTo(secondaryMonthlyAmount) > 0) {
				// 已完成项目含税费的总金额(企业付出去的金额)已经大于第二档每月金额, 使用第二档计算保证金
				actualDepositRate = compCrowdCost.getSecondaryDepositRate();
			} else {
				// 默认比例
				actualDepositRate = compCrowdCost.getDepositRate();
			}
		}

		double actualCrowdCostRate = 0;
		double actualProfitRate = 0;
		double baseTaxRate = NumberUtil.safeDouble(compCrowdCost.getBaseTaxRate());
		if (compCrowdCost.getSub() == PartnerCrowdSub.OWN) {
			// 自己的企业 实际分成比例 = 企业基础服务费率 - 实际保证金率 - 自己实际众包成本比例
			actualCrowdCostRate = ownActualCrowdCostRate;
			actualProfitRate = baseTaxRate - actualDepositRate - actualCrowdCostRate;
		} else if (compCrowdCost.getSub() == PartnerCrowdSub.SUB) {
			// 获取下级合伙人的实际众包成本比例
			PartnerAccount subPartnerAccount = new PartnerAccount().selectOne(Condition.create().eq("partnerid", partnerid));
			CrowdsourceProjectSumDto subProjectSum = getCrowdPartnerMonthTotalAmount(partnerid, month);
			BigDecimal subTotalAmount = subProjectSum.getProjectTotalAmount().add(subProjectSum.getProjectTotalTaxfee());
			if (subTotalAmount.compareTo(subPartnerAccount.getCrowdCostSecondaryAmount()) > 0) {
				actualCrowdCostRate = subPartnerAccount.getCrowdCostSecondaryRate();
			} else {
				actualCrowdCostRate = subPartnerAccount.getCrowdCostPrimaryRate();
			}
			// 下级合伙人分成比例:
			double subProfitRate = baseTaxRate - actualDepositRate - actualCrowdCostRate;
			if (subProfitRate < 0) subProfitRate = 0;
			double ownProfitRate = baseTaxRate - actualDepositRate - ownActualCrowdCostRate;
			if (ownProfitRate <0) ownProfitRate = 0;
			// 下级合伙人:实际分成利润比例 = 自己的实际众包利润比例 - 下级合伙人的众包利润比例
			actualProfitRate = ownProfitRate - subProfitRate;
		}
		if (actualProfitRate < 0) actualProfitRate = 0;
		BigDecimal profit = compCrowdCost.getProjectAmount().multiply(BigDecimal.valueOf(actualProfitRate));
		compCrowdCost.setActualCrowdCostRate(actualCrowdCostRate)
				.setActualDepositRate(actualDepositRate)
				.setActualProfitRate(actualProfitRate)
				.setProfit(profit);
	}

}
